1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package sun.font;
27
28 import java.awt.Font;
29 import java.awt.FontFormatException;
30 import java.awt.GraphicsEnvironment;
31 import java.awt.geom.Point2D;
32 import java.io.FileNotFoundException;
33 import java.io.IOException;
34 import java.io.RandomAccessFile;
35 import java.io.UnsupportedEncodingException;
36 import java.nio.ByteBuffer;
37 import java.nio.CharBuffer;
38 import java.nio.IntBuffer;
39 import java.nio.ShortBuffer;
40 import java.nio.channels.ClosedChannelException;
41 import java.nio.channels.FileChannel;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.Map;
45 import java.util.Locale;
46 import sun.java2d.Disposer;
47 import sun.java2d.DisposerRecord;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class TrueTypeFont extends FileFont {
64
65
66 public static final int cmapTag = 0x636D6170;
67 public static final int glyfTag = 0x676C7966;
68 public static final int headTag = 0x68656164;
69 public static final int hheaTag = 0x68686561;
70 public static final int hmtxTag = 0x686D7478;
71 public static final int locaTag = 0x6C6F6361;
72 public static final int maxpTag = 0x6D617870;
73 public static final int nameTag = 0x6E616D65;
74 public static final int postTag = 0x706F7374;
75 public static final int os_2Tag = 0x4F532F32;
76
77
78 public static final int GDEFTag = 0x47444546;
79 public static final int GPOSTag = 0x47504F53;
80 public static final int GSUBTag = 0x47535542;
81 public static final int mortTag = 0x6D6F7274;
82
83
84 public static final int fdscTag = 0x66647363;
85 public static final int fvarTag = 0x66766172;
86 public static final int featTag = 0x66656174;
87 public static final int EBLCTag = 0x45424C43;
88 public static final int gaspTag = 0x67617370;
89
90
91 public static final int ttcfTag = 0x74746366;
92 public static final int v1ttTag = 0x00010000;
93 public static final int trueTag = 0x74727565;
94 public static final int ottoTag = 0x4f54544f;
95
96
97 public static final int MS_PLATFORM_ID = 3;
98
99 public static final short ENGLISH_LOCALE_ID = 0x0409;
100 public static final int FAMILY_NAME_ID = 1;
101
102 public static final int FULL_NAME_ID = 4;
103 public static final int POSTSCRIPT_NAME_ID = 6;
104
105 private static final short US_LCID = 0x0409;
106
107 private static Map<String, Short> lcidMap;
108
109 class DirectoryEntry {
110 int tag;
111 int offset;
112 int length;
113 }
114
115
116
117
118
119
120
121
122
123 private static class TTDisposerRecord implements DisposerRecord {
124
125 FileChannel channel = null;
126
127 public synchronized void dispose() {
128 try {
129 if (channel != null) {
130 channel.close();
131 }
132 } catch (IOException e) {
133 } finally {
134 channel = null;
135 }
136 }
137 }
138
139 TTDisposerRecord disposerRecord = new TTDisposerRecord();
140
141
142 int fontIndex = 0;
143
144
145 int directoryCount = 1;
146
147
148 int directoryOffset;
149
150
151 int numTables;
152
153
154 DirectoryEntry []tableDirectory;
155
156
157
158
159
160
161
162
163
164 private boolean supportsJA;
165 private boolean supportsCJK;
166
167
168
169
170 private Locale nameLocale;
171 private String localeFamilyName;
172 private String localeFullName;
173
174
175
176
177
178
179
180
181
182
183 public TrueTypeFont(String platname, Object nativeNames, int fIndex,
184 boolean javaRasterizer)
185 throws FontFormatException {
186 super(platname, nativeNames);
187 useJavaRasterizer = javaRasterizer;
188 fontRank = Font2D.TTF_RANK;
189 try {
190 verify();
191 init(fIndex);
192 } catch (Throwable t) {
193 close();
194 if (t instanceof FontFormatException) {
195 throw (FontFormatException)t;
196 } else {
197 throw new FontFormatException("Unexpected runtime exception.");
198 }
199 }
200 Disposer.addObjectRecord(this, disposerRecord);
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214 @Override
215 protected boolean checkUseNatives() {
216 if (checkedNatives) {
217 return useNatives;
218 }
219 if (!FontUtilities.isSolaris || useJavaRasterizer ||
220 FontUtilities.useT2K || nativeNames == null ||
221 getDirectoryEntry(EBLCTag) != null ||
222 GraphicsEnvironment.isHeadless()) {
223 checkedNatives = true;
224 return false;
225 } else if (nativeNames instanceof String) {
226 String name = (String)nativeNames;
227
228 if (name.indexOf("8859") > 0) {
229 checkedNatives = true;
230 return false;
231 } else if (NativeFont.hasExternalBitmaps(name)) {
232 nativeFonts = new NativeFont[1];
233 try {
234 nativeFonts[0] = new NativeFont(name, true);
235
236
237
238 useNatives = true;
239 } catch (FontFormatException e) {
240 nativeFonts = null;
241 }
242 }
243 } else if (nativeNames instanceof String[]) {
244 String[] natNames = (String[])nativeNames;
245 int numNames = natNames.length;
246 boolean externalBitmaps = false;
247 for (int nn = 0; nn < numNames; nn++) {
248 if (natNames[nn].indexOf("8859") > 0) {
249 checkedNatives = true;
250 return false;
251 } else if (NativeFont.hasExternalBitmaps(natNames[nn])) {
252 externalBitmaps = true;
253 }
254 }
255 if (!externalBitmaps) {
256 checkedNatives = true;
257 return false;
258 }
259 useNatives = true;
260 nativeFonts = new NativeFont[numNames];
261 for (int nn = 0; nn < numNames; nn++) {
262 try {
263 nativeFonts[nn] = new NativeFont(natNames[nn], true);
264 } catch (FontFormatException e) {
265 useNatives = false;
266 nativeFonts = null;
267 }
268 }
269 }
270 if (useNatives) {
271 glyphToCharMap = new char[getMapper().getNumGlyphs()];
272 }
273 checkedNatives = true;
274 return useNatives;
275 }
276
277
278
279
280
281
282
283
284
285 private synchronized FileChannel open() throws FontFormatException {
286 if (disposerRecord.channel == null) {
287 if (FontUtilities.isLogging()) {
288 FontUtilities.getLogger().info("open TTF: " + platName);
289 }
290 try {
291 RandomAccessFile raf = (RandomAccessFile)
292 java.security.AccessController.doPrivileged(
293 new java.security.PrivilegedAction() {
294 public Object run() {
295 try {
296 return new RandomAccessFile(platName, "r");
297 } catch (FileNotFoundException ffne) {
298 }
299 return null;
300 }
301 });
302 disposerRecord.channel = raf.getChannel();
303 fileSize = (int)disposerRecord.channel.size();
304 FontManager fm = FontManagerFactory.getInstance();
305 if (fm instanceof SunFontManager) {
306 ((SunFontManager) fm).addToPool(this);
307 }
308 } catch (NullPointerException e) {
309 close();
310 throw new FontFormatException(e.toString());
311 } catch (ClosedChannelException e) {
312
313
314
315
316
317 Thread.interrupted();
318 close();
319 open();
320 } catch (IOException e) {
321 close();
322 throw new FontFormatException(e.toString());
323 }
324 }
325 return disposerRecord.channel;
326 }
327
328 protected synchronized void close() {
329 disposerRecord.dispose();
330 }
331
332
333 int readBlock(ByteBuffer buffer, int offset, int length) {
334 int bread = 0;
335 try {
336 synchronized (this) {
337 if (disposerRecord.channel == null) {
338 open();
339 }
340 if (offset + length > fileSize) {
341 if (offset >= fileSize) {
342
343
344
345
346
347
348
349
350
351 if (FontUtilities.isLogging()) {
352 String msg = "Read offset is " + offset +
353 " file size is " + fileSize+
354 " file is " + platName;
355 FontUtilities.getLogger().severe(msg);
356 }
357 return -1;
358 } else {
359 length = fileSize - offset;
360 }
361 }
362 buffer.clear();
363 disposerRecord.channel.position(offset);
364 while (bread < length) {
365 int cnt = disposerRecord.channel.read(buffer);
366 if (cnt == -1) {
367 String msg = "Unexpected EOF " + this;
368 int currSize = (int)disposerRecord.channel.size();
369 if (currSize != fileSize) {
370 msg += " File size was " + fileSize +
371 " and now is " + currSize;
372 }
373 if (FontUtilities.isLogging()) {
374 FontUtilities.getLogger().severe(msg);
375 }
376
377
378
379
380
381
382
383
384
385
386 if (bread > length/2 || bread > 16384) {
387 buffer.flip();
388 if (FontUtilities.isLogging()) {
389 msg = "Returning " + bread +
390 " bytes instead of " + length;
391 FontUtilities.getLogger().severe(msg);
392 }
393 } else {
394 bread = -1;
395 }
396 throw new IOException(msg);
397 }
398 bread += cnt;
399 }
400 buffer.flip();
401 if (bread > length) {
402 bread = length;
403 }
404 }
405 } catch (FontFormatException e) {
406 if (FontUtilities.isLogging()) {
407 FontUtilities.getLogger().severe(
408 "While reading " + platName, e);
409 }
410 bread = -1;
411 deregisterFontAndClearStrikeCache();
412 } catch (ClosedChannelException e) {
413
414
415
416 Thread.interrupted();
417 close();
418 return readBlock(buffer, offset, length);
419 } catch (IOException e) {
420
421
422
423
424
425
426
427 if (FontUtilities.isLogging()) {
428 FontUtilities.getLogger().severe(
429 "While reading " + platName, e);
430 }
431 if (bread == 0) {
432 bread = -1;
433 deregisterFontAndClearStrikeCache();
434 }
435 }
436 return bread;
437 }
438
439 ByteBuffer readBlock(int offset, int length) {
440
441 ByteBuffer buffer = ByteBuffer.allocate(length);
442 try {
443 synchronized (this) {
444 if (disposerRecord.channel == null) {
445 open();
446 }
447 if (offset + length > fileSize) {
448 if (offset > fileSize) {
449 return null;
450 } else {
451 buffer = ByteBuffer.allocate(fileSize-offset);
452 }
453 }
454 disposerRecord.channel.position(offset);
455 disposerRecord.channel.read(buffer);
456 buffer.flip();
457 }
458 } catch (FontFormatException e) {
459 return null;
460 } catch (ClosedChannelException e) {
461
462
463
464 Thread.interrupted();
465 close();
466 readBlock(buffer, offset, length);
467 } catch (IOException e) {
468 return null;
469 }
470 return buffer;
471 }
472
473
474
475
476
477
478
479 byte[] readBytes(int offset, int length) {
480 ByteBuffer buffer = readBlock(offset, length);
481 if (buffer.hasArray()) {
482 return buffer.array();
483 } else {
484 byte[] bufferBytes = new byte[buffer.limit()];
485 buffer.get(bufferBytes);
486 return bufferBytes;
487 }
488 }
489
490 private void verify() throws FontFormatException {
491 open();
492 }
493
494
495 private static final int TTCHEADERSIZE = 12;
496 private static final int DIRECTORYHEADERSIZE = 12;
497 private static final int DIRECTORYENTRYSIZE = 16;
498
499 protected void init(int fIndex) throws FontFormatException {
500 int headerOffset = 0;
501 ByteBuffer buffer = readBlock(0, TTCHEADERSIZE);
502 try {
503 switch (buffer.getInt()) {
504
505 case ttcfTag:
506 buffer.getInt();
507 directoryCount = buffer.getInt();
508 if (fIndex >= directoryCount) {
509 throw new FontFormatException("Bad collection index");
510 }
511 fontIndex = fIndex;
512 buffer = readBlock(TTCHEADERSIZE+4*fIndex, 4);
513 headerOffset = buffer.getInt();
514 break;
515
516 case v1ttTag:
517 case trueTag:
518 case ottoTag:
519 break;
520
521 default:
522 throw new FontFormatException("Unsupported sfnt " +
523 getPublicFileName());
524 }
525
526
527
528
529
530
531
532 buffer = readBlock(headerOffset+4, 2);
533 numTables = buffer.getShort();
534 directoryOffset = headerOffset+DIRECTORYHEADERSIZE;
535 ByteBuffer bbuffer = readBlock(directoryOffset,
536 numTables*DIRECTORYENTRYSIZE);
537 IntBuffer ibuffer = bbuffer.asIntBuffer();
538 DirectoryEntry table;
539 tableDirectory = new DirectoryEntry[numTables];
540 for (int i=0; i<numTables;i++) {
541 tableDirectory[i] = table = new DirectoryEntry();
542 table.tag = ibuffer.get();
543 ibuffer.get();
544 table.offset = ibuffer.get();
545 table.length = ibuffer.get();
546 if (table.offset + table.length > fileSize) {
547 throw new FontFormatException("bad table, tag="+table.tag);
548 }
549 }
550 initNames();
551 } catch (Exception e) {
552 if (FontUtilities.isLogging()) {
553 FontUtilities.getLogger().severe(e.toString());
554 }
555 if (e instanceof FontFormatException) {
556 throw (FontFormatException)e;
557 } else {
558 throw new FontFormatException(e.toString());
559 }
560 }
561 if (familyName == null || fullName == null) {
562 throw new FontFormatException("Font name not found");
563 }
564
565
566
567
568 ByteBuffer os2_Table = getTableBuffer(os_2Tag);
569 setStyle(os2_Table);
570 setCJKSupport(os2_Table);
571 }
572
573
574
575
576
577
578
579
580 static final String encoding_mapping[] = {
581 "cp1252",
582 "cp1250",
583 "cp1251",
584 "cp1253",
585 "cp1254",
586 "cp1255",
587 "cp1256",
588 "cp1257",
589 "",
590 "",
591 "",
592 "",
593 "",
594 "",
595 "",
596 "",
597 "ms874",
598 "ms932",
599 "gbk",
600 "ms949",
601 "ms950",
602 "ms1361",
603 "",
604 "",
605 "",
606 "",
607 "",
608 "",
609 "",
610 "",
611 "",
612 "",
613 };
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628 private static final String languages[][] = {
629
630
631 { "en", "ca", "da", "de", "es", "fi", "fr", "is", "it",
632 "nl", "no", "pt", "sq", "sv", },
633
634
635 { "cs", "cz", "et", "hr", "hu", "nr", "pl", "ro", "sk",
636 "sl", "sq", "sr", },
637
638
639 { "bg", "mk", "ru", "sh", "uk" },
640
641
642 { "el" },
643
644
645 { "tr" },
646
647
648 { "he" },
649
650
651 { "ar" },
652
653
654 { "et", "lt", "lv" },
655
656
657 { "th" },
658
659
660 { "ja" },
661
662
663 { "zh", "zh_CN", },
664
665
666 { "ko" },
667
668
669 { "zh_HK", "zh_TW", },
670
671
672 { "ko" },
673 };
674
675 private static final String codePages[] = {
676 "cp1252",
677 "cp1250",
678 "cp1251",
679 "cp1253",
680 "cp1254",
681 "cp1255",
682 "cp1256",
683 "cp1257",
684 "ms874",
685 "ms932",
686 "gbk",
687 "ms949",
688 "ms950",
689 "ms1361",
690 };
691
692 private static String defaultCodePage = null;
693 static String getCodePage() {
694
695 if (defaultCodePage != null) {
696 return defaultCodePage;
697 }
698
699 if (FontUtilities.isWindows) {
700 defaultCodePage =
701 (String)java.security.AccessController.doPrivileged(
702 new sun.security.action.GetPropertyAction("file.encoding"));
703 } else {
704 if (languages.length != codePages.length) {
705 throw new InternalError("wrong code pages array length");
706 }
707 Locale locale = sun.awt.SunToolkit.getStartupLocale();
708
709 String language = locale.getLanguage();
710 if (language != null) {
711 if (language.equals("zh")) {
712 String country = locale.getCountry();
713 if (country != null) {
714 language = language + "_" + country;
715 }
716 }
717 for (int i=0; i<languages.length;i++) {
718 for (int l=0;l<languages[i].length; l++) {
719 if (language.equals(languages[i][l])) {
720 defaultCodePage = codePages[i];
721 return defaultCodePage;
722 }
723 }
724 }
725 }
726 }
727 if (defaultCodePage == null) {
728 defaultCodePage = "";
729 }
730 return defaultCodePage;
731 }
732
733
734 public static final int reserved_bits1 = 0x80000000;
735 public static final int reserved_bits2 = 0x0000ffff;
736 @Override
737 boolean supportsEncoding(String encoding) {
738 if (encoding == null) {
739 encoding = getCodePage();
740 }
741 if ("".equals(encoding)) {
742 return false;
743 }
744
745 encoding = encoding.toLowerCase();
746
747
748
749
750
751
752
753
754 if (encoding.equals("gb18030")) {
755 encoding = "gbk";
756 } else if (encoding.equals("ms950_hkscs")) {
757 encoding = "ms950";
758 }
759
760 ByteBuffer buffer = getTableBuffer(os_2Tag);
761
762 if (buffer == null || buffer.capacity() < 86) {
763 return false;
764 }
765
766 int range1 = buffer.getInt(78);
767 int range2 = buffer.getInt(82);
768
769
770
771
772
773
774
775
776
777 for (int em=0; em<encoding_mapping.length; em++) {
778 if (encoding_mapping[em].equals(encoding)) {
779 if (((1 << em) & range1) != 0) {
780 return true;
781 }
782 }
783 }
784 return false;
785 }
786
787
788
789 private void setCJKSupport(ByteBuffer os2Table) {
790
791 if (os2Table == null || os2Table.capacity() < 50) {
792 return;
793 }
794 int range2 = os2Table.getInt(46);
795
796
797
798
799
800
801 supportsCJK = ((range2 & 0x29bf0000) != 0);
802
803
804
805
806
807
808
809
810 supportsJA = ((range2 & 0x60000) != 0);
811 }
812
813 boolean supportsJA() {
814 return supportsJA;
815 }
816
817 ByteBuffer getTableBuffer(int tag) {
818 DirectoryEntry entry = null;
819
820 for (int i=0;i<numTables;i++) {
821 if (tableDirectory[i].tag == tag) {
822 entry = tableDirectory[i];
823 break;
824 }
825 }
826 if (entry == null || entry.length == 0 ||
827 entry.offset+entry.length > fileSize) {
828 return null;
829 }
830
831 int bread = 0;
832 ByteBuffer buffer = ByteBuffer.allocate(entry.length);
833 synchronized (this) {
834 try {
835 if (disposerRecord.channel == null) {
836 open();
837 }
838 disposerRecord.channel.position(entry.offset);
839 bread = disposerRecord.channel.read(buffer);
840 buffer.flip();
841 } catch (ClosedChannelException e) {
842
843
844
845 Thread.interrupted();
846 close();
847 return getTableBuffer(tag);
848 } catch (IOException e) {
849 return null;
850 } catch (FontFormatException e) {
851 return null;
852 }
853
854 if (bread < entry.length) {
855 return null;
856 } else {
857 return buffer;
858 }
859 }
860 }
861
862
863 long getLayoutTableCache() {
864 try {
865 return getScaler().getLayoutTableCache();
866 } catch(FontScalerException fe) {
867 return 0L;
868 }
869 }
870
871 @Override
872 byte[] getTableBytes(int tag) {
873 ByteBuffer buffer = getTableBuffer(tag);
874 if (buffer == null) {
875 return null;
876 } else if (buffer.hasArray()) {
877 try {
878 return buffer.array();
879 } catch (Exception re) {
880 }
881 }
882 byte []data = new byte[getTableSize(tag)];
883 buffer.get(data);
884 return data;
885 }
886
887 int getTableSize(int tag) {
888 for (int i=0;i<numTables;i++) {
889 if (tableDirectory[i].tag == tag) {
890 return tableDirectory[i].length;
891 }
892 }
893 return 0;
894 }
895
896 int getTableOffset(int tag) {
897 for (int i=0;i<numTables;i++) {
898 if (tableDirectory[i].tag == tag) {
899 return tableDirectory[i].offset;
900 }
901 }
902 return 0;
903 }
904
905 DirectoryEntry getDirectoryEntry(int tag) {
906 for (int i=0;i<numTables;i++) {
907 if (tableDirectory[i].tag == tag) {
908 return tableDirectory[i];
909 }
910 }
911 return null;
912 }
913
914
915
916
917 boolean useEmbeddedBitmapsForSize(int ptSize) {
918 if (!supportsCJK) {
919 return false;
920 }
921 if (getDirectoryEntry(EBLCTag) == null) {
922 return false;
923 }
924 ByteBuffer eblcTable = getTableBuffer(EBLCTag);
925 int numSizes = eblcTable.getInt(4);
926
927
928
929
930 for (int i=0;i<numSizes;i++) {
931 int ppemY = eblcTable.get(8+(i*48)+45) &0xff;
932 if (ppemY == ptSize) {
933 return true;
934 }
935 }
936 return false;
937 }
938
939 public String getFullName() {
940 return fullName;
941 }
942
943
944
945
946 @Override
947 protected void setStyle() {
948 setStyle(getTableBuffer(os_2Tag));
949 }
950
951
952
953
954
955
956
957
958
959
960
961
962 private static final int fsSelectionItalicBit = 0x00001;
963 private static final int fsSelectionBoldBit = 0x00020;
964 private static final int fsSelectionRegularBit = 0x00040;
965 private void setStyle(ByteBuffer os_2Table) {
966
967 if (os_2Table == null || os_2Table.capacity() < 64) {
968 super.setStyle();
969 return;
970 }
971 int fsSelection = os_2Table.getChar(62) & 0xffff;
972 int italic = fsSelection & fsSelectionItalicBit;
973 int bold = fsSelection & fsSelectionBoldBit;
974 int regular = fsSelection & fsSelectionRegularBit;
975
976
977
978 if (regular!=0 && ((italic|bold)!=0)) {
979
980 super.setStyle();
981 return;
982 } else if ((regular|italic|bold) == 0) {
983
984 super.setStyle();
985 return;
986 }
987 switch (bold|italic) {
988 case fsSelectionItalicBit:
989 style = Font.ITALIC;
990 break;
991 case fsSelectionBoldBit:
992 if (FontUtilities.isSolaris && platName.endsWith("HG-GothicB.ttf")) {
993
994
995
996 style = Font.PLAIN;
997 } else {
998 style = Font.BOLD;
999 }
1000 break;
1001 case fsSelectionBoldBit|fsSelectionItalicBit:
1002 style = Font.BOLD|Font.ITALIC;
1003 }
1004 }
1005
1006 private float stSize, stPos, ulSize, ulPos;
1007
1008 private void setStrikethroughMetrics(ByteBuffer os_2Table, int upem) {
1009 if (os_2Table == null || os_2Table.capacity() < 30 || upem < 0) {
1010 stSize = .05f;
1011 stPos = -.4f;
1012 return;
1013 }
1014 ShortBuffer sb = os_2Table.asShortBuffer();
1015 stSize = sb.get(13) / (float)upem;
1016 stPos = -sb.get(14) / (float)upem;
1017 }
1018
1019 private void setUnderlineMetrics(ByteBuffer postTable, int upem) {
1020 if (postTable == null || postTable.capacity() < 12 || upem < 0) {
1021 ulSize = .05f;
1022 ulPos = .1f;
1023 return;
1024 }
1025 ShortBuffer sb = postTable.asShortBuffer();
1026 ulSize = sb.get(5) / (float)upem;
1027 ulPos = -sb.get(4) / (float)upem;
1028 }
1029
1030 @Override
1031 public void getStyleMetrics(float pointSize, float[] metrics, int offset) {
1032
1033 if (ulSize == 0f && ulPos == 0f) {
1034
1035 ByteBuffer head_Table = getTableBuffer(headTag);
1036 int upem = -1;
1037 if (head_Table != null && head_Table.capacity() >= 18) {
1038 ShortBuffer sb = head_Table.asShortBuffer();
1039 upem = sb.get(9) & 0xffff;
1040 }
1041
1042 ByteBuffer os2_Table = getTableBuffer(os_2Tag);
1043 setStrikethroughMetrics(os2_Table, upem);
1044
1045 ByteBuffer post_Table = getTableBuffer(postTag);
1046 setUnderlineMetrics(post_Table, upem);
1047 }
1048
1049 metrics[offset] = stPos * pointSize;
1050 metrics[offset+1] = stSize * pointSize;
1051
1052 metrics[offset+2] = ulPos * pointSize;
1053 metrics[offset+3] = ulSize * pointSize;
1054 }
1055
1056 private String makeString(byte[] bytes, int len, short encoding) {
1057
1058
1059
1060
1061
1062
1063
1064 if (encoding >=2 && encoding <= 6) {
1065 byte[] oldbytes = bytes;
1066 int oldlen = len;
1067 bytes = new byte[oldlen];
1068 len = 0;
1069 for (int i=0; i<oldlen; i++) {
1070 if (oldbytes[i] != 0) {
1071 bytes[len++] = oldbytes[i];
1072 }
1073 }
1074 }
1075
1076 String charset;
1077 switch (encoding) {
1078 case 1: charset = "UTF-16"; break;
1079 case 0: charset = "UTF-16"; break;
1080 case 2: charset = "SJIS"; break;
1081 case 3: charset = "GBK"; break;
1082 case 4: charset = "MS950"; break;
1083 case 5: charset = "EUC_KR"; break;
1084 case 6: charset = "Johab"; break;
1085 default: charset = "UTF-16"; break;
1086 }
1087
1088 try {
1089 return new String(bytes, 0, len, charset);
1090 } catch (UnsupportedEncodingException e) {
1091 if (FontUtilities.isLogging()) {
1092 FontUtilities.getLogger().warning(e + " EncodingID=" + encoding);
1093 }
1094 return new String(bytes, 0, len);
1095 } catch (Throwable t) {
1096 return null;
1097 }
1098 }
1099
1100 protected void initNames() {
1101
1102 byte[] name = new byte[256];
1103 ByteBuffer buffer = getTableBuffer(nameTag);
1104
1105 if (buffer != null) {
1106 ShortBuffer sbuffer = buffer.asShortBuffer();
1107 sbuffer.get();
1108 short numRecords = sbuffer.get();
1109
1110
1111
1112
1113
1114 int stringPtr = sbuffer.get() & 0xffff;
1115
1116 nameLocale = sun.awt.SunToolkit.getStartupLocale();
1117 short nameLocaleID = getLCIDFromLocale(nameLocale);
1118
1119 for (int i=0; i<numRecords; i++) {
1120 short platformID = sbuffer.get();
1121 if (platformID != MS_PLATFORM_ID) {
1122 sbuffer.position(sbuffer.position()+5);
1123 continue;
1124 }
1125 short encodingID = sbuffer.get();
1126 short langID = sbuffer.get();
1127 short nameID = sbuffer.get();
1128 int nameLen = ((int) sbuffer.get()) & 0xffff;
1129 int namePtr = (((int) sbuffer.get()) & 0xffff) + stringPtr;
1130 String tmpName = null;
1131 switch (nameID) {
1132
1133 case FAMILY_NAME_ID:
1134
1135 if (familyName == null || langID == ENGLISH_LOCALE_ID ||
1136 langID == nameLocaleID)
1137 {
1138 buffer.position(namePtr);
1139 buffer.get(name, 0, nameLen);
1140 tmpName = makeString(name, nameLen, encodingID);
1141
1142 if (familyName == null || langID == ENGLISH_LOCALE_ID){
1143 familyName = tmpName;
1144 }
1145 if (langID == nameLocaleID) {
1146 localeFamilyName = tmpName;
1147 }
1148 }
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 break;
1162
1163 case FULL_NAME_ID:
1164
1165 if (fullName == null || langID == ENGLISH_LOCALE_ID ||
1166 langID == nameLocaleID)
1167 {
1168 buffer.position(namePtr);
1169 buffer.get(name, 0, nameLen);
1170 tmpName = makeString(name, nameLen, encodingID);
1171
1172 if (fullName == null || langID == ENGLISH_LOCALE_ID) {
1173 fullName = tmpName;
1174 }
1175 if (langID == nameLocaleID) {
1176 localeFullName = tmpName;
1177 }
1178 }
1179 break;
1180 }
1181 }
1182 if (localeFamilyName == null) {
1183 localeFamilyName = familyName;
1184 }
1185 if (localeFullName == null) {
1186 localeFullName = fullName;
1187 }
1188 }
1189 }
1190
1191
1192
1193
1194
1195
1196 protected String lookupName(short findLocaleID, int findNameID) {
1197 String foundName = null;
1198 byte[] name = new byte[1024];
1199
1200 ByteBuffer buffer = getTableBuffer(nameTag);
1201 if (buffer != null) {
1202 ShortBuffer sbuffer = buffer.asShortBuffer();
1203 sbuffer.get();
1204 short numRecords = sbuffer.get();
1205
1206
1207
1208
1209
1210
1211 int stringPtr = ((int) sbuffer.get()) & 0xffff;
1212
1213 for (int i=0; i<numRecords; i++) {
1214 short platformID = sbuffer.get();
1215 if (platformID != MS_PLATFORM_ID) {
1216 sbuffer.position(sbuffer.position()+5);
1217 continue;
1218 }
1219 short encodingID = sbuffer.get();
1220 short langID = sbuffer.get();
1221 short nameID = sbuffer.get();
1222 int nameLen = ((int) sbuffer.get()) & 0xffff;
1223 int namePtr = (((int) sbuffer.get()) & 0xffff) + stringPtr;
1224 if (nameID == findNameID &&
1225 ((foundName == null && langID == ENGLISH_LOCALE_ID)
1226 || langID == findLocaleID)) {
1227 buffer.position(namePtr);
1228 buffer.get(name, 0, nameLen);
1229 foundName = makeString(name, nameLen, encodingID);
1230 if (langID == findLocaleID) {
1231 return foundName;
1232 }
1233 }
1234 }
1235 }
1236 return foundName;
1237 }
1238
1239
1240
1241
1242 public int getFontCount() {
1243 return directoryCount;
1244 }
1245
1246 protected synchronized FontScaler getScaler() {
1247 if (scaler == null) {
1248 scaler = FontScaler.getScaler(this, fontIndex,
1249 supportsCJK, fileSize);
1250 }
1251 return scaler;
1252 }
1253
1254
1255
1256
1257
1258 @Override
1259 public String getPostscriptName() {
1260 String name = lookupName(ENGLISH_LOCALE_ID, POSTSCRIPT_NAME_ID);
1261 if (name == null) {
1262 return fullName;
1263 } else {
1264 return name;
1265 }
1266 }
1267
1268 @Override
1269 public String getFontName(Locale locale) {
1270 if (locale == null) {
1271 return fullName;
1272 } else if (locale.equals(nameLocale) && localeFullName != null) {
1273 return localeFullName;
1274 } else {
1275 short localeID = getLCIDFromLocale(locale);
1276 String name = lookupName(localeID, FULL_NAME_ID);
1277 if (name == null) {
1278 return fullName;
1279 } else {
1280 return name;
1281 }
1282 }
1283 }
1284
1285
1286
1287
1288 private static void addLCIDMapEntry(Map<String, Short> map,
1289 String key, short value) {
1290 map.put(key, Short.valueOf(value));
1291 }
1292
1293 private static synchronized void createLCIDMap() {
1294 if (lcidMap != null) {
1295 return;
1296 }
1297
1298 Map<String, Short> map = new HashMap<String, Short>(200);
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326 addLCIDMapEntry(map, "ar", (short) 0x0401);
1327 addLCIDMapEntry(map, "bg", (short) 0x0402);
1328 addLCIDMapEntry(map, "ca", (short) 0x0403);
1329 addLCIDMapEntry(map, "zh", (short) 0x0404);
1330 addLCIDMapEntry(map, "cs", (short) 0x0405);
1331 addLCIDMapEntry(map, "da", (short) 0x0406);
1332 addLCIDMapEntry(map, "de", (short) 0x0407);
1333 addLCIDMapEntry(map, "el", (short) 0x0408);
1334 addLCIDMapEntry(map, "es", (short) 0x040a);
1335 addLCIDMapEntry(map, "fi", (short) 0x040b);
1336 addLCIDMapEntry(map, "fr", (short) 0x040c);
1337 addLCIDMapEntry(map, "iw", (short) 0x040d);
1338 addLCIDMapEntry(map, "hu", (short) 0x040e);
1339 addLCIDMapEntry(map, "is", (short) 0x040f);
1340 addLCIDMapEntry(map, "it", (short) 0x0410);
1341 addLCIDMapEntry(map, "ja", (short) 0x0411);
1342 addLCIDMapEntry(map, "ko", (short) 0x0412);
1343 addLCIDMapEntry(map, "nl", (short) 0x0413);
1344 addLCIDMapEntry(map, "no", (short) 0x0414);
1345 addLCIDMapEntry(map, "pl", (short) 0x0415);
1346 addLCIDMapEntry(map, "pt", (short) 0x0416);
1347 addLCIDMapEntry(map, "rm", (short) 0x0417);
1348 addLCIDMapEntry(map, "ro", (short) 0x0418);
1349 addLCIDMapEntry(map, "ru", (short) 0x0419);
1350 addLCIDMapEntry(map, "hr", (short) 0x041a);
1351 addLCIDMapEntry(map, "sk", (short) 0x041b);
1352 addLCIDMapEntry(map, "sq", (short) 0x041c);
1353 addLCIDMapEntry(map, "sv", (short) 0x041d);
1354 addLCIDMapEntry(map, "th", (short) 0x041e);
1355 addLCIDMapEntry(map, "tr", (short) 0x041f);
1356 addLCIDMapEntry(map, "ur", (short) 0x0420);
1357 addLCIDMapEntry(map, "in", (short) 0x0421);
1358 addLCIDMapEntry(map, "uk", (short) 0x0422);
1359 addLCIDMapEntry(map, "be", (short) 0x0423);
1360 addLCIDMapEntry(map, "sl", (short) 0x0424);
1361 addLCIDMapEntry(map, "et", (short) 0x0425);
1362 addLCIDMapEntry(map, "lv", (short) 0x0426);
1363 addLCIDMapEntry(map, "lt", (short) 0x0427);
1364 addLCIDMapEntry(map, "fa", (short) 0x0429);
1365 addLCIDMapEntry(map, "vi", (short) 0x042a);
1366 addLCIDMapEntry(map, "hy", (short) 0x042b);
1367 addLCIDMapEntry(map, "eu", (short) 0x042d);
1368 addLCIDMapEntry(map, "mk", (short) 0x042f);
1369 addLCIDMapEntry(map, "tn", (short) 0x0432);
1370 addLCIDMapEntry(map, "xh", (short) 0x0434);
1371 addLCIDMapEntry(map, "zu", (short) 0x0435);
1372 addLCIDMapEntry(map, "af", (short) 0x0436);
1373 addLCIDMapEntry(map, "ka", (short) 0x0437);
1374 addLCIDMapEntry(map, "fo", (short) 0x0438);
1375 addLCIDMapEntry(map, "hi", (short) 0x0439);
1376 addLCIDMapEntry(map, "mt", (short) 0x043a);
1377 addLCIDMapEntry(map, "se", (short) 0x043b);
1378 addLCIDMapEntry(map, "gd", (short) 0x043c);
1379 addLCIDMapEntry(map, "ms", (short) 0x043e);
1380 addLCIDMapEntry(map, "kk", (short) 0x043f);
1381 addLCIDMapEntry(map, "ky", (short) 0x0440);
1382 addLCIDMapEntry(map, "sw", (short) 0x0441);
1383 addLCIDMapEntry(map, "tt", (short) 0x0444);
1384 addLCIDMapEntry(map, "bn", (short) 0x0445);
1385 addLCIDMapEntry(map, "pa", (short) 0x0446);
1386 addLCIDMapEntry(map, "gu", (short) 0x0447);
1387 addLCIDMapEntry(map, "ta", (short) 0x0449);
1388 addLCIDMapEntry(map, "te", (short) 0x044a);
1389 addLCIDMapEntry(map, "kn", (short) 0x044b);
1390 addLCIDMapEntry(map, "ml", (short) 0x044c);
1391 addLCIDMapEntry(map, "mr", (short) 0x044e);
1392 addLCIDMapEntry(map, "sa", (short) 0x044f);
1393 addLCIDMapEntry(map, "mn", (short) 0x0450);
1394 addLCIDMapEntry(map, "cy", (short) 0x0452);
1395 addLCIDMapEntry(map, "gl", (short) 0x0456);
1396 addLCIDMapEntry(map, "dv", (short) 0x0465);
1397 addLCIDMapEntry(map, "qu", (short) 0x046b);
1398 addLCIDMapEntry(map, "mi", (short) 0x0481);
1399 addLCIDMapEntry(map, "ar_IQ", (short) 0x0801);
1400 addLCIDMapEntry(map, "zh_CN", (short) 0x0804);
1401 addLCIDMapEntry(map, "de_CH", (short) 0x0807);
1402 addLCIDMapEntry(map, "en_GB", (short) 0x0809);
1403 addLCIDMapEntry(map, "es_MX", (short) 0x080a);
1404 addLCIDMapEntry(map, "fr_BE", (short) 0x080c);
1405 addLCIDMapEntry(map, "it_CH", (short) 0x0810);
1406 addLCIDMapEntry(map, "nl_BE", (short) 0x0813);
1407 addLCIDMapEntry(map, "no_NO_NY", (short) 0x0814);
1408 addLCIDMapEntry(map, "pt_PT", (short) 0x0816);
1409 addLCIDMapEntry(map, "ro_MD", (short) 0x0818);
1410 addLCIDMapEntry(map, "ru_MD", (short) 0x0819);
1411 addLCIDMapEntry(map, "sr_CS", (short) 0x081a);
1412 addLCIDMapEntry(map, "sv_FI", (short) 0x081d);
1413 addLCIDMapEntry(map, "az_AZ", (short) 0x082c);
1414 addLCIDMapEntry(map, "se_SE", (short) 0x083b);
1415 addLCIDMapEntry(map, "ga_IE", (short) 0x083c);
1416 addLCIDMapEntry(map, "ms_BN", (short) 0x083e);
1417 addLCIDMapEntry(map, "uz_UZ", (short) 0x0843);
1418 addLCIDMapEntry(map, "qu_EC", (short) 0x086b);
1419 addLCIDMapEntry(map, "ar_EG", (short) 0x0c01);
1420 addLCIDMapEntry(map, "zh_HK", (short) 0x0c04);
1421 addLCIDMapEntry(map, "de_AT", (short) 0x0c07);
1422 addLCIDMapEntry(map, "en_AU", (short) 0x0c09);
1423 addLCIDMapEntry(map, "fr_CA", (short) 0x0c0c);
1424 addLCIDMapEntry(map, "sr_CS", (short) 0x0c1a);
1425 addLCIDMapEntry(map, "se_FI", (short) 0x0c3b);
1426 addLCIDMapEntry(map, "qu_PE", (short) 0x0c6b);
1427 addLCIDMapEntry(map, "ar_LY", (short) 0x1001);
1428 addLCIDMapEntry(map, "zh_SG", (short) 0x1004);
1429 addLCIDMapEntry(map, "de_LU", (short) 0x1007);
1430 addLCIDMapEntry(map, "en_CA", (short) 0x1009);
1431 addLCIDMapEntry(map, "es_GT", (short) 0x100a);
1432 addLCIDMapEntry(map, "fr_CH", (short) 0x100c);
1433 addLCIDMapEntry(map, "hr_BA", (short) 0x101a);
1434 addLCIDMapEntry(map, "ar_DZ", (short) 0x1401);
1435 addLCIDMapEntry(map, "zh_MO", (short) 0x1404);
1436 addLCIDMapEntry(map, "de_LI", (short) 0x1407);
1437 addLCIDMapEntry(map, "en_NZ", (short) 0x1409);
1438 addLCIDMapEntry(map, "es_CR", (short) 0x140a);
1439 addLCIDMapEntry(map, "fr_LU", (short) 0x140c);
1440 addLCIDMapEntry(map, "bs_BA", (short) 0x141a);
1441 addLCIDMapEntry(map, "ar_MA", (short) 0x1801);
1442 addLCIDMapEntry(map, "en_IE", (short) 0x1809);
1443 addLCIDMapEntry(map, "es_PA", (short) 0x180a);
1444 addLCIDMapEntry(map, "fr_MC", (short) 0x180c);
1445 addLCIDMapEntry(map, "sr_BA", (short) 0x181a);
1446 addLCIDMapEntry(map, "ar_TN", (short) 0x1c01);
1447 addLCIDMapEntry(map, "en_ZA", (short) 0x1c09);
1448 addLCIDMapEntry(map, "es_DO", (short) 0x1c0a);
1449 addLCIDMapEntry(map, "sr_BA", (short) 0x1c1a);
1450 addLCIDMapEntry(map, "ar_OM", (short) 0x2001);
1451 addLCIDMapEntry(map, "en_JM", (short) 0x2009);
1452 addLCIDMapEntry(map, "es_VE", (short) 0x200a);
1453 addLCIDMapEntry(map, "ar_YE", (short) 0x2401);
1454 addLCIDMapEntry(map, "es_CO", (short) 0x240a);
1455 addLCIDMapEntry(map, "ar_SY", (short) 0x2801);
1456 addLCIDMapEntry(map, "en_BZ", (short) 0x2809);
1457 addLCIDMapEntry(map, "es_PE", (short) 0x280a);
1458 addLCIDMapEntry(map, "ar_JO", (short) 0x2c01);
1459 addLCIDMapEntry(map, "en_TT", (short) 0x2c09);
1460 addLCIDMapEntry(map, "es_AR", (short) 0x2c0a);
1461 addLCIDMapEntry(map, "ar_LB", (short) 0x3001);
1462 addLCIDMapEntry(map, "en_ZW", (short) 0x3009);
1463 addLCIDMapEntry(map, "es_EC", (short) 0x300a);
1464 addLCIDMapEntry(map, "ar_KW", (short) 0x3401);
1465 addLCIDMapEntry(map, "en_PH", (short) 0x3409);
1466 addLCIDMapEntry(map, "es_CL", (short) 0x340a);
1467 addLCIDMapEntry(map, "ar_AE", (short) 0x3801);
1468 addLCIDMapEntry(map, "es_UY", (short) 0x380a);
1469 addLCIDMapEntry(map, "ar_BH", (short) 0x3c01);
1470 addLCIDMapEntry(map, "es_PY", (short) 0x3c0a);
1471 addLCIDMapEntry(map, "ar_QA", (short) 0x4001);
1472 addLCIDMapEntry(map, "es_BO", (short) 0x400a);
1473 addLCIDMapEntry(map, "es_SV", (short) 0x440a);
1474 addLCIDMapEntry(map, "es_HN", (short) 0x480a);
1475 addLCIDMapEntry(map, "es_NI", (short) 0x4c0a);
1476 addLCIDMapEntry(map, "es_PR", (short) 0x500a);
1477
1478 lcidMap = map;
1479 }
1480
1481 private static short getLCIDFromLocale(Locale locale) {
1482
1483 if (locale.equals(Locale.US)) {
1484 return US_LCID;
1485 }
1486
1487 if (lcidMap == null) {
1488 createLCIDMap();
1489 }
1490
1491 String key = locale.toString();
1492 while (!"".equals(key)) {
1493 Short lcidObject = (Short) lcidMap.get(key);
1494 if (lcidObject != null) {
1495 return lcidObject.shortValue();
1496 }
1497 int pos = key.lastIndexOf('_');
1498 if (pos < 1) {
1499 return US_LCID;
1500 }
1501 key = key.substring(0, pos);
1502 }
1503
1504 return US_LCID;
1505 }
1506
1507 @Override
1508 public String getFamilyName(Locale locale) {
1509 if (locale == null) {
1510 return familyName;
1511 } else if (locale.equals(nameLocale) && localeFamilyName != null) {
1512 return localeFamilyName;
1513 } else {
1514 short localeID = getLCIDFromLocale(locale);
1515 String name = lookupName(localeID, FAMILY_NAME_ID);
1516 if (name == null) {
1517 return familyName;
1518 } else {
1519 return name;
1520 }
1521 }
1522 }
1523
1524 public CharToGlyphMapper getMapper() {
1525 if (mapper == null) {
1526 mapper = new TrueTypeGlyphMapper(this);
1527 }
1528 return mapper;
1529 }
1530
1531
1532
1533
1534
1535 protected void initAllNames(int requestedID, HashSet names) {
1536
1537 byte[] name = new byte[256];
1538 ByteBuffer buffer = getTableBuffer(nameTag);
1539
1540 if (buffer != null) {
1541 ShortBuffer sbuffer = buffer.asShortBuffer();
1542 sbuffer.get();
1543 short numRecords = sbuffer.get();
1544
1545
1546
1547
1548
1549
1550 int stringPtr = ((int) sbuffer.get()) & 0xffff;
1551 for (int i=0; i<numRecords; i++) {
1552 short platformID = sbuffer.get();
1553 if (platformID != MS_PLATFORM_ID) {
1554 sbuffer.position(sbuffer.position()+5);
1555 continue;
1556 }
1557 short encodingID = sbuffer.get();
1558 short langID = sbuffer.get();
1559 short nameID = sbuffer.get();
1560 int nameLen = ((int) sbuffer.get()) & 0xffff;
1561 int namePtr = (((int) sbuffer.get()) & 0xffff) + stringPtr;
1562
1563 if (nameID == requestedID) {
1564 buffer.position(namePtr);
1565 buffer.get(name, 0, nameLen);
1566 names.add(makeString(name, nameLen, encodingID));
1567 }
1568 }
1569 }
1570 }
1571
1572 String[] getAllFamilyNames() {
1573 HashSet aSet = new HashSet();
1574 try {
1575 initAllNames(FAMILY_NAME_ID, aSet);
1576 } catch (Exception e) {
1577
1578 }
1579 return (String[])aSet.toArray(new String[0]);
1580 }
1581
1582 String[] getAllFullNames() {
1583 HashSet aSet = new HashSet();
1584 try {
1585 initAllNames(FULL_NAME_ID, aSet);
1586 } catch (Exception e) {
1587
1588 }
1589 return (String[])aSet.toArray(new String[0]);
1590 }
1591
1592
1593
1594 @Override
1595 Point2D.Float getGlyphPoint(long pScalerContext,
1596 int glyphCode, int ptNumber) {
1597 try {
1598 return getScaler().getGlyphPoint(pScalerContext,
1599 glyphCode, ptNumber);
1600 } catch(FontScalerException fe) {
1601 return null;
1602 }
1603 }
1604
1605 private char[] gaspTable;
1606
1607 private char[] getGaspTable() {
1608
1609 if (gaspTable != null) {
1610 return gaspTable;
1611 }
1612
1613 ByteBuffer buffer = getTableBuffer(gaspTag);
1614 if (buffer == null) {
1615 return gaspTable = new char[0];
1616 }
1617
1618 CharBuffer cbuffer = buffer.asCharBuffer();
1619 char format = cbuffer.get();
1620
1621
1622
1623
1624 if (format > 1) {
1625 return gaspTable = new char[0];
1626 }
1627
1628 char numRanges = cbuffer.get();
1629 if (4+numRanges*4 > getTableSize(gaspTag)) {
1630 return gaspTable = new char[0];
1631 }
1632 gaspTable = new char[2*numRanges];
1633 cbuffer.get(gaspTable);
1634 return gaspTable;
1635 }
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656 @Override
1657 public boolean useAAForPtSize(int ptsize) {
1658
1659 char[] gasp = getGaspTable();
1660 if (gasp.length > 0) {
1661 for (int i=0;i<gasp.length;i+=2) {
1662 if (ptsize <= gasp[i]) {
1663 return ((gasp[i+1] & 0x2) != 0);
1664 }
1665 }
1666 return true;
1667 }
1668
1669 if (style == Font.BOLD) {
1670 return true;
1671 } else {
1672 return ptsize <= 8 || ptsize >= 18;
1673 }
1674 }
1675
1676 @Override
1677 public boolean hasSupplementaryChars() {
1678 return ((TrueTypeGlyphMapper)getMapper()).hasSupplementaryChars();
1679 }
1680
1681 @Override
1682 public String toString() {
1683 return "** TrueType Font: Family="+familyName+ " Name="+fullName+
1684 " style="+style+" fileName="+getPublicFileName();
1685 }
1686 }